package com.example.first.thread;

import java.util.Random;
import java.util.concurrent.*;

/**
 * @Author LSQ
 * @Description ThreadPoolExecutor extends AbstractExecutorService, AbstractExecutorService implements ExecutorService
 * @date 2021/8/5 21:13
 * @Version 1.0
 */

/**
 * 多线程： ThreadPoolExecutor(具体类) -> AbstractExecutorService (抽象类) -> ExecutorService (接口) -> Executor (接口)
 */

public class LearnExecutor1 {
    private static final int CORE_POOL_SIZE = 3;
    private static final int MAX_POOL_SIZE = 5;
    private static final int QUEUE_CAPACITY = 1000;

    public static void compute(int costTime) {

        try {
            TimeUnit.SECONDS.sleep(costTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        // ExecutorService executorService = new ThreadPoolExecutor(2, 2, 60, new ArrayBlockingQueue<Runnable>(10),threadFactory);


   /*
       自定义的线程池
       ExecutorService executorService = new ThreadPoolExecutor(3, 6,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());*/

        // 自定义3个核心线程，最多5个线程的线程池，任务队列用有界阻塞队列

        ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE,
                0L, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(QUEUE_CAPACITY));


/*        Runnable runnable1 = () -> {
            System.out.println("running1...");
            try {
                TimeUnit.SECONDS.sleep(8);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Runnable runnable2 = () -> {
            System.out.println("running2...");
            try {
                TimeUnit.SECONDS.sleep(6);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        executorService.submit(runnable2);
        */

        // for循环会一次性提交n个任务
        for (int i = 0; i < 900; i++) {
            Random random = new Random();
            int taskExecuteTime = random.nextInt(10);
            // System.out.printf("running task %d%n", i);
            int taskNum = i;
            Runnable runnable = () -> {
                System.out.printf("Task [ %d ] [ %s ] will cost : %d seconds%n", taskNum, Thread.currentThread().getName(), taskExecuteTime);

                compute(taskExecuteTime);

            };

            // System.out.printf("Task [ %d ] submit\n ", i);
            executorService.submit(runnable);

        }

        /*
        关闭线程池

        System.out.println("print thread pool is shutdown: " + executorService.isShutdown());
        System.out.println("print thread pool is Terminated: " + executorService.isTerminated());

         */
        executorService.shutdown();

    }
}


/*

打印结果

Task [ 1 ] [ pool-1-thread-2 ] will cost : 3 seconds
Task [ 11 ] [ pool-1-thread-4 ] will cost : 1 seconds
Task [ 12 ] [ pool-1-thread-5 ] will cost : 1 seconds
Task [ 2 ] [ pool-1-thread-3 ] will cost : 7 seconds
Task [ 0 ] [ pool-1-thread-1 ] will cost : 1 seconds
Task [ 3 ] [ pool-1-thread-5 ] will cost : 8 seconds
Task [ 5 ] [ pool-1-thread-1 ] will cost : 4 seconds
Task [ 4 ] [ pool-1-thread-4 ] will cost : 7 seconds
Task [ 6 ] [ pool-1-thread-2 ] will cost : 6 seconds
Task [ 7 ] [ pool-1-thread-1 ] will cost : 0 seconds
Task [ 8 ] [ pool-1-thread-1 ] will cost : 2 seconds
Task [ 9 ] [ pool-1-thread-3 ] will cost : 6 seconds
Task [ 10 ] [ pool-1-thread-1 ] will cost : 5 seconds

结论：

1、一开始线程 1 2 3 4 5 同时执行 任务 0 1 2 11 12，后面还有任务 3 4 5 6 7 8 9 10在任务队列里面
2、线程1 4 5 处理任务只耗时1秒，接着从任务队列里面取任务
3、如果设置的workQueue队列很长，大于要执行的任务数，就轮不到线程 4和5去执行了
 */

/*
（注意执行顺序）


核心代码



    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated （饱和）
         * and so reject the task.
         */
    /*
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
                c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();               // 重新获取线程数
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)   // workerCountOf计算线程数，如果是0，要执行addWorker
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
        }

 */
